home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / EditFields / EditFields.c < prev    next >
Text File  |  1992-09-10  |  14KB  |  606 lines

  1. /****************************************************************************************
  2. *
  3. *
  4. *        Edit Field Library- .h Definition File
  5. *
  6. *        9/9/92    ©ImproVision UK. Written by Graham Cox.
  7. *
  8. ****************************************************************************************/
  9.  
  10.  
  11. #include        "EditFields.h"
  12.  
  13.  
  14. extended
  15. GPCstr2num(void *s)
  16. {
  17.     short n = 1;
  18.     char p = 0;
  19.     decimal d;
  20.     extended x;
  21.     
  22.     decstr68k(s, &n, &d, &p, FPSTR2DEC);
  23.     fp68k(&d, &x, FDEC2X);
  24.     return(x);
  25. }
  26.  
  27.  
  28. void
  29. GPCnum2str(decform *f, extended x, void *s)
  30. {
  31.     decimal d;
  32.     
  33.     fp68k(f, &x, &d, FX2DEC);
  34.     decstr68k(f, &d, s, FDEC2STR);
  35. }
  36.  
  37.  
  38. CopyString(Ptr s1,Ptr s2)
  39. {        
  40.     short    byteCount;
  41.     
  42.     byteCount=*s1+1;
  43.     BlockMove(s1,s2,byteCount);
  44. }
  45.  
  46.  
  47. ConcatString(Ptr s1,Ptr s2)
  48. {
  49.     /* given pointers to two pascal strings, this function concatenates the characters of
  50.         s2 on to the end of s1. No range checking is performed. */
  51.         
  52.     short    byteCount,offset;
  53.     Ptr        temp;
  54.     
  55.     temp=s1;                        /* remember old pointer         */
  56.     offset=*s1+1;                    /* length of first string         */
  57.     s1+=offset;                        /* point at end of string +1     */
  58.     byteCount=*s2;                       /* length of second string        */
  59.     s2++;                            /* first char of second string    */
  60.     BlockMove(s2,s1,byteCount);        /* copy chars                    */
  61.     *temp=offset+byteCount-1;        /* update length                */
  62. }
  63.  
  64.  
  65. EditFieldHdl NewEditField(Rect *bounds,int IDnum,Str255 *theText)
  66. {
  67.     /* creates a new edit field record with the given parameters. The record is not 
  68.         automatically linked to the fields list- you have to do this */
  69.         
  70.     EditFieldHdl    temp;
  71.     
  72.     temp = (EditFieldHdl) NewHandleClear(sizeof(EditField));
  73.     if (temp != NIL) {
  74.         (*temp)->efID = IDnum;
  75.         (*temp)->edViewRect = *bounds;
  76.         (*temp)->edFlags = fieldNoRestriction;
  77.         (*temp)->upLimit = 256;
  78.         (*temp)->lowLimit = 1;
  79.         HLock((Handle) temp);
  80.         CopyString((Ptr)theText,(Ptr)&(*temp)->edFieldText);
  81.         HUnlock((Handle) temp);
  82.         (*temp)->nextField = NIL;
  83.     }
  84.     return(temp);
  85. }
  86.  
  87.  
  88. void LinkEditField(EFListHdl efList,EditFieldHdl eField)
  89. {
  90.     /* pushes the given eField onto the top of the stack of fields in the main struct */
  91.     
  92.     if (efList != NIL && eField != NIL) {
  93.         (*eField)->nextField = (*efList)->efListHead;
  94.         (*efList)->efListHead = eField;
  95.     }
  96. }
  97.  
  98.  
  99. void Draw1Field(EditFieldHdl theField)
  100. {
  101.     /* draws the given field using TextBox */
  102.     
  103.     Rect    tView,tFrame;
  104.     
  105.     if (theField != NIL) {
  106.         tView = (*theField)->edViewRect;
  107.         tFrame = tView;
  108.         InsetRect(&tFrame,-3,-3);
  109.         FrameRect(&tFrame);
  110.         
  111.         HLock((Handle) theField);
  112.         TextBox(&(*theField)->edFieldText[1],
  113.                     (*theField)->edFieldText[0],
  114.                     &tView,
  115.                     teJustLeft);
  116.                     
  117.         HUnlock((Handle) theField);
  118.     }
  119. }
  120.  
  121.  
  122. void SetFieldText(EditFieldHdl theField,Str255 *theText)
  123. {
  124.     /* sets the text in the given field to the supplied string. To update the display,
  125.         you will need to do more! */
  126.         
  127.     if (theField != NIL) {
  128.         CopyString((Ptr)theText,(Ptr)&(*theField)->edFieldText);
  129.         (*theField)->edFlags |= fieldDataChanged;
  130.     }
  131. }
  132.  
  133.  
  134. void GetFieldText(EditFieldHdl theField,Str255 *theText)
  135. {
  136.     /* returns the string in the associated field */
  137.     
  138.     if (theField != NIL)
  139.         CopyString((Ptr)&(*theField)->edFieldText,(Ptr)theText);
  140. }
  141.  
  142.  
  143. void SetFPField(EditFieldHdl theField,extended fpValue,int nDecPlaces)
  144. {
  145.     /* converts the given floating point value to a string with the given number of
  146.         decimal places, then sets the text of the field to this string. */
  147.         
  148.     DecForm        fpFormat;
  149.     Str255        fpText;
  150.     
  151.     if (theField != NIL) {
  152.         fpFormat.style = FIXEDDECIMAL;
  153.         fpFormat.digits = nDecPlaces;
  154.         
  155.         GPCnum2str(&fpFormat,fpValue,&fpText);    
  156.         SetFieldText(theField,&fpText);
  157.         
  158.     }
  159. }
  160.  
  161.  
  162. extended GetFPField(EditFieldHdl theField)
  163. {
  164.     /* converts the given field's text string to a floating point value. */
  165.     
  166.     Str255        fpText;
  167.     
  168.     if (theField != NIL) {
  169.         GetFieldText(theField,&fpText);
  170.         return(GPCstr2num(&fpText));
  171.     }
  172. }
  173.  
  174.  
  175. void SetEdFlags(EditFieldHdl theField,long theFlags)
  176. {
  177.     /* sets the flags field to the given value */
  178.     
  179.     if (theField != NIL)
  180.         (*theField)->edFlags = theFlags;
  181. }
  182.  
  183.  
  184. long GetEdFlags(EditFieldHdl theField)
  185. {
  186.     /* returns the field flags field */
  187.     
  188.     if (theField != NIL)
  189.         return((*theField)->edFlags);
  190.     else
  191.         return(-1L);
  192. }
  193.  
  194.  
  195. EFListHdl    NewEditFieldList(WindowPtr ownerWindow)
  196. {
  197.     /* creates a new edit field list record, preinitialised with the owner window, and a
  198.         new TERecord incorporating the ownerWindow's grafPort. No fields are yet attached
  199.         to the record- these are created with NewEditField and linked with LinkEditField */
  200.         
  201.     EFListHdl    temp;
  202.     GrafPtr        savePort;
  203.     Rect        tRect;
  204.     
  205.     temp = (EFListHdl)NewHandleClear(sizeof(EFList));
  206.     if (temp != NIL) {
  207.         (*temp)->efOwner = ownerWindow;
  208.         (*temp)->numFields = 0;
  209.         (*temp)->currentField = 0;
  210.         (*temp)->efListHead = NIL;
  211.         GetPort(&savePort);
  212.         SetPort(ownerWindow);
  213.         
  214.         tRect = ownerWindow->portRect;
  215.         (*temp)->efText = TENew(&tRect,&tRect);
  216.         
  217.         SetPort(savePort);
  218.     }
  219.     return(temp);
  220. }
  221.  
  222.  
  223. void DisposeEditFieldList(EFListHdl theList)
  224. {
  225.     /* disposes of ef list and all internal structures */
  226.     
  227.     EditFieldHdl    temp,efNext;
  228.     
  229.     if (theList != NIL) {
  230.         
  231.         temp = (*theList)->efListHead;
  232.         
  233.         while (temp != NIL) {
  234.             efNext = (*temp)->nextField;
  235.             DisposHandle(temp);
  236.             temp = efNext;
  237.         }
  238.         
  239.         TEDispose((*theList)->efText);
  240.         
  241.         DisposHandle(theList);
  242.     }
  243. }
  244.  
  245.  
  246. EditFieldHdl    GetIndexedField(EFListHdl efList,int theIndex)
  247. {
  248.     /* returns the handle of the edit field record having the ID number theIndex. If
  249.         the index does not exist in the list, NIL is returned */
  250.         
  251.     EditFieldHdl    temp = NIL;
  252.     
  253.     if (efList != NIL) {
  254.         temp = (*efList)->efListHead;
  255.         while (temp != NIL) {
  256.             if ((*temp)->efID == theIndex)
  257.                 break;
  258.             else
  259.                 temp = (*temp)->nextField;
  260.         }
  261.     }
  262.     return(temp);
  263. }
  264.  
  265.  
  266. void IncDecCurrentField(EFListHdl efList,Boolean incDecFlag)
  267. {
  268.     /* increment or decrements currently selected edit field. This is designed to be
  269.         called repeatedly in a loop, and uses a delay to avoid this occurring too fast. */
  270.         
  271.     long            tDelay,fValue,efFlags,uLimit,lLimit;
  272.     EditFieldHdl    theField;
  273.     Str255            fText;
  274.     CharsHandle        eChars;
  275.     TEHandle        theText;
  276.     DecForm            fpFormat;
  277.     extended        fpValue;
  278.  
  279.     if (efList != NIL) {
  280.         theText = (*efList)->efText;
  281.         if (theText != NIL) {
  282.             TEDeactivate(theText);
  283.             eChars = TEGetText(theText);
  284.             BlockMove(*eChars,&fText[1],(*theText)->teLength);
  285.             fText[0] = (*theText)->teLength;
  286.             
  287.             theField = GetIndexedField(efList,(*efList)->currentField);
  288.             if (theField != NIL) {
  289.                 efFlags = GetEdFlags(theField);
  290.                 
  291.                 uLimit = (*theField)->upLimit;
  292.                 lLimit = (*theField)->lowLimit;
  293.                 
  294.                 if ((efFlags & (fieldNumeric + fieldFloatingPoint + fieldConvertTicks))
  295.                         == (fieldNumeric + fieldFloatingPoint + fieldConvertTicks)) {
  296.                     /* need floating point data */
  297.                     
  298.                     fpFormat.style = FIXEDDECIMAL;
  299.                     fpFormat.digits = 2;
  300.                     
  301.                     fpValue = GPCstr2num(&fText);
  302.                     if (incDecFlag) {
  303.                         fpValue -= 0.01667;    
  304.                         if ((fpValue * 60) < lLimit)
  305.                             fpValue = (extended)lLimit/60;
  306.                     }
  307.                     else {
  308.                         fpValue += 0.01667;
  309.                         if ((fpValue * 60) > uLimit)
  310.                             fpValue = (extended)uLimit/60;
  311.                     }
  312.                     
  313.                     GPCnum2str(&fpFormat,fpValue,&fText);
  314.                 }
  315.                 else {
  316.                     StringToNum(&fText,&fValue);
  317.                     
  318.                     if (incDecFlag) {
  319.                         fValue --;    
  320.                         if (fValue < (lLimit +1))
  321.                             fValue = lLimit;
  322.                     }
  323.                     else {
  324.                         fValue ++;
  325.                         if (fValue > (uLimit -1))
  326.                             fValue = uLimit;
  327.                     }
  328.                     
  329.                     NumToString(fValue,&fText);
  330.                 }
  331.                 TESetText(&fText[1],fText[0],theText);
  332.                 TEUpdate(&(*theText)->viewRect,theText);
  333.                 Delay(3,&tDelay);
  334.             }
  335.             TEActivate(theText);
  336.         }
  337.     }
  338. }
  339.  
  340.  
  341. void DrawEditFields(EFListHdl efList)
  342. {
  343.     /* from the given record, draws the edit fields in the current port. The non-selected
  344.         fields are updated using TextBox, the selected one updated using TEUpdate */
  345.     
  346.     EditFieldHdl    temp;
  347.     Rect            tView,tFrame;
  348.     int                eSelect;
  349.     
  350.     if (efList != NIL) {
  351.         temp = (*efList)->efListHead;
  352.         eSelect = (*efList)->currentField;
  353.         
  354.         while(temp != NIL) {
  355.             if ((*temp)->efID == eSelect) {
  356.                 tView = (*temp)->edViewRect;
  357.                 tFrame = tView;
  358.                 InsetRect(&tFrame,-3,-3);
  359.                 FrameRect(&tFrame);
  360.                 TEUpdate(&tView,(*efList)->efText);
  361.             }
  362.             else
  363.                 Draw1Field(temp);
  364.                 
  365.             temp = (*temp)->nextField;
  366.         }
  367.     }    
  368. }
  369.  
  370.  
  371. void SelectEditField(EFListHdl efList,int theIndex)
  372. {
  373.     /* sets up the text record so that the indexed field is selected for editing. The
  374.         text in the existing record is copied out to the field identified by the 
  375.         edFieldSelected value, the new text copied to the record, and the internal value
  376.         updated */
  377.         
  378.     EditFieldHdl    oldField,newField;
  379.     TEHandle        theEdRec;
  380.     CharsHandle        teText;
  381.     int                oldIndex;
  382.     Rect            eView;
  383.     GrafPtr            savePort;
  384.     
  385.     if (efList != NIL) {
  386.         GetPort(&savePort);
  387.         SetPort((*efList)->efOwner);
  388.         
  389.         theEdRec = (*efList)->efText;
  390.         if (theEdRec != NIL) {
  391.             oldIndex = (*efList)->currentField;
  392.             oldField = GetIndexedField(efList,oldIndex);
  393.             if ((oldField != NIL) && !((*oldField)->edFlags & fieldDataChanged)) {
  394.                 teText = TEGetText(theEdRec);
  395.                 HLock((Handle) oldField);
  396.                 BlockMove(*teText,&(*oldField)->edFieldText[1],(*theEdRec)->teLength);
  397.                 (*oldField)->edFieldText[0] = (*theEdRec)->teLength;
  398.                 HUnlock((Handle) oldField);
  399.                 
  400.             }
  401.             if ((oldIndex != theIndex) || ((*oldField)->edFlags & fieldDataChanged)) {
  402.                 TEDeactivate(theEdRec);
  403.                 newField = GetIndexedField(efList,theIndex);
  404.                 (*newField)->edFlags &= (0xFFFFFFFF - fieldDataChanged);
  405.                 
  406.                 if (newField != NIL) {
  407.                     (*efList)->currentField = theIndex;
  408.                     HLock((Handle) newField);
  409.                     TESetText(&(*newField)->edFieldText[1],
  410.                                 (*newField)->edFieldText[0],theEdRec);
  411.                                 
  412.                     HUnlock((Handle) newField);
  413.                     
  414.                     eView = (*newField)->edViewRect;
  415.                     (*theEdRec)->destRect = eView;
  416.                     (*theEdRec)->viewRect = eView;
  417.                     (*theEdRec)->destRect.right += 256;
  418.                     
  419.                     TECalText(theEdRec);
  420.                     Draw1Field(newField);
  421.                 }
  422.                 TEActivate(theEdRec);
  423.             }
  424.         }
  425.         SetPort(savePort);
  426.     }
  427. }
  428.  
  429.  
  430. int    FindEditField(EFListHdl efList,Point mClick)
  431. {
  432.     /* returns the ID number of the edit field containing the point, or zero if none do.
  433.         This is used to hit test the edit fields when the window is clicked */
  434.         
  435.     EditFieldHdl    eField;
  436.     Rect            efRect;
  437.     int                efClicked = 0;
  438.     
  439.     if (efList != NIL) {
  440.         eField = (*efList)->efListHead;
  441.         
  442.         while (eField != NIL) {
  443.             efRect = (*eField)->edViewRect;
  444.             InsetRect(&efRect,-2,-2);
  445.             
  446.             if (PtInRect(mClick,&efRect)) {
  447.                 efClicked = (*eField)->efID;
  448.                 break;
  449.             }
  450.             else
  451.                 eField = (*eField)->nextField;
  452.         }
  453.     }
  454.     return(efClicked);
  455. }
  456.  
  457.  
  458.  
  459. void EFIdle(EFListHdl    efList)
  460. {
  461.     /* call frequently to blink the caret in edit fields */
  462.     
  463.     
  464.     if (efList != NIL)
  465.         TEIdle((*efList)->efText);
  466. }
  467.  
  468.  
  469. int CheckFieldLimits(EditFieldHdl theField,EFListHdl efList)
  470. {
  471.     /* gets the current field value, if numeric, and checks it's current setting against
  472.         the bounds. If outside, the value is changed to be pinned to the bounds */
  473.     
  474.     long        fValue,efFlags,uLimit,lLimit;
  475.     extended    fValueFP;
  476.     Str255        fText;
  477.     int            efsSave;
  478.     
  479.     if (theField != NIL && efList != NIL) {
  480.         efFlags = GetEdFlags(theField);
  481.         efsSave = (*efList)->currentField;
  482.         
  483.         if (efsSave == (*theField)->efID)
  484.             SelectEditField(efList,efsSave);             /* ensure field valid */
  485.         
  486.         if (efFlags & fieldNumeric) {
  487.             if (efFlags & fieldFloatingPoint) {
  488.                 fValueFP = GetFPField(theField);
  489.                 if (efFlags & fieldConvertTicks)
  490.                     fValue = (fValueFP + 0.02) * 60;
  491.                 else
  492.                     fValue = fValueFP;
  493.             }
  494.             else {
  495.                 GetFieldText(theField,&fText);
  496.                 StringToNum(&fText,&fValue);
  497.             }
  498.             
  499.             uLimit = (*theField)->upLimit;
  500.             lLimit = (*theField)->lowLimit;
  501.             
  502.             if (fValue > uLimit) {
  503.                 fValue = uLimit;
  504.                 SetAndUpdateField(efList,(*theField)->efID,fValue);
  505.                 SysBeep(1);
  506.                 TESetSelect(0,32767,(*efList)->efText);
  507.                 return(FALSE);
  508.             }
  509.             else {
  510.                 if (fValue < lLimit) {
  511.                     fValue = lLimit;
  512.                     SetAndUpdateField(efList,(*theField)->efID,fValue);
  513.                     SysBeep(1);
  514.                     TESetSelect(0,32767,(*efList)->efText);
  515.                     return(FALSE);
  516.                 }
  517.             }
  518.         }
  519.     }
  520.     return(TRUE);
  521. }
  522.  
  523.  
  524.  
  525.  
  526. void KeyField(EFListHdl efList,char theKey)
  527. {
  528.     /* passes keys to the current field. This examines the flags of the field to deter-
  529.         mine what characters are filtered out. Control keys must already have been
  530.         filtered and dealt with */
  531.     
  532.     int                efSelect;
  533.     EditFieldHdl    eField;    
  534.     long            efFlags;
  535.     Boolean            charInRange;
  536.     
  537.     if (efList != NIL) {
  538.         efSelect = (*efList)->currentField;
  539.         eField = GetIndexedField(efList,efSelect);
  540.         efFlags = GetEdFlags(eField);
  541.         
  542.         if (theKey == 0x08 || (theKey >= 0x1C && theKey <= 0x1F))
  543.             TEKey(theKey,(*efList)->efText);
  544.         else {
  545.             if (efFlags != fieldNoRestriction) {
  546.                 if (efFlags & fieldNumeric) {
  547.                     charInRange = !(theKey < 0x30 || theKey > 0x39);
  548.                     if (efFlags & fieldFloatingPoint)
  549.                         charInRange = charInRange || (theKey == 0x2E);
  550.                 }
  551.                 else {
  552.                     if (efFlags & fieldAlphabetic)
  553.                         charInRange = !(theKey < 0x41 || theKey > 0x7A);
  554.                 }
  555.                 if (charInRange)
  556.                     TEKey(theKey,(*efList)->efText);
  557.                 else
  558.                     SysBeep(1);
  559.             }
  560.             else
  561.                 TEKey(theKey,(*efList)->efText);
  562.         }
  563.     }    
  564. }
  565.  
  566.  
  567. void SetAndUpdateField(EFListHdl efList,int theFieldID,long fValue)
  568. {
  569.     /* given a fieldID number and a value, the value is converted to a string, set into
  570.         the identified field (if it exists!) and the whole caboodle is updated. */
  571.     
  572.     Str255            fText;
  573.     EditFieldHdl    theField;
  574.     int                saveSelect;
  575.     long            efFlags;
  576.     extended        fValueFP;
  577.     
  578.     if (efList != NIL) {
  579.         theField = GetIndexedField(efList,theFieldID);
  580.         if (theField != NIL) {
  581.             efFlags = GetEdFlags(theField);
  582.             saveSelect = (*efList)->currentField;
  583.             
  584.             if ((efFlags & (fieldNumeric + fieldFloatingPoint))
  585.                     == (fieldNumeric + fieldFloatingPoint)) {
  586.                 if (efFlags & fieldConvertTicks)
  587.                     fValueFP = (extended)fValue/60;
  588.                 else
  589.                     fValueFP = (extended)fValue;    
  590.                     
  591.                 SetFPField(theField,fValueFP,2);    
  592.             }
  593.             else {
  594.                 NumToString(fValue,&fText);
  595.                 SetFieldText(theField,&fText);
  596.             }
  597.             (*efList)->currentField = 0;                /* fudge the update mechanism! */
  598.             SelectEditField(efList,theFieldID);            /* keep text in order & update */
  599.             SelectEditField(efList,saveSelect);            /* restore the old field selection */
  600.         }
  601.     }    
  602. }    
  603.  
  604.  
  605.  
  606.